package org.huzhp.gateway.exception;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import org.huzhp.gateway.service.AbstractAuditLogService;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: Sentinel配置返回格式
 * @Author: huzp
 * @CreateDate: 2020/3/13 18:59
 * @Version: 1.0
 */
public class SentinelBlockRequestHandler implements BlockRequestHandler {

    private AbstractAuditLogService auditLogService;

    @Override
    public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable ex) {
        // 返回http状态码为200
        return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(buildErrorResult(exchange, ex)));
    }


    private Map buildErrorResult(ServerWebExchange exchange, Throwable ex) {
        ServerHttpRequest request = exchange.getRequest();
        Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        Map error = new HashMap();
        error.put("timestamp", new Date());
        error.put("path", request.getPath().toString());
        error.put("status", HttpStatus.TOO_MANY_REQUESTS.value());
        error.put("error", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
        error.put("message", ex.getClass().getSimpleName());
        error.put("requestId", request.getId());
        error.put("routeId", route.getId());

        Long startTime = exchange.getAttribute("startTime");
        Long executeTime = null;
        if (startTime != null) {
            executeTime = (System.currentTimeMillis() - startTime);
        }
        error.put("executeTime", executeTime);

        auditLogService.logError(error, request);

        return error;
    }

    public void setAuditLogService(AbstractAuditLogService auditLogService) {
        this.auditLogService = auditLogService;
    }
}
